use crate::structx::adapter::target::{SpecificTarget, Target};
/*
适配器模式是一种结构型设计模式， 它能使接口不兼容的对象能够相互合作。

创建一个适配器。 这是一个特殊的对象， 能够转换对象接口， 使其能与其他对象进行交互。
适配器模式通过封装对象将复杂的转换过程隐藏于幕后。 被封装的对象甚至察觉不到适配器的存在。 例如， 你可以使用一个将所有数据转换为英制单位 （如英尺和英里） 的适配器封装运行于米和千米单位制中的对象。

适配器实现与其中一个现有对象兼容的接口。
现有对象可以使用该接口安全地调用适配器方法。
适配器方法被调用后将以另一个对象兼容的格式和顺序将请求传递给该对象。

对象适配器
实现时使用了构成原则： 适配器实现了其中一个对象的接口， 并对另一个对象进行封装。 所有流行的编程语言都可以实现适配器。


类适配器
这一实现使用了继承机制： 适配器同时继承两个对象的接口。 请注意， 这种方式仅能在支持多重继承的编程语言中实现， 例如 C++。




桥接模式通常会于开发前期进行设计， 使你能够将程序的各个部分独立开来以便开发。 另一方面， 适配器模式通常在已有程序中使用， 让相互不兼容的类能很好地合作。

适配器可以对已有对象的接口进行修改， 装饰模式则能在不改变对象接口的前提下强化对象功能。 此外， 装饰还支持递归组合， 适配器则无法实现。

适配器能为被封装对象提供不同的接口， 代理模式能为对象提供相同的接口， 装饰则能为对象提供加强的接口。

外观模式为现有对象定义了一个新接口， 适配器则会试图运用已有的接口。 适配器通常只封装一个对象， 外观通常会作用于整个对象子系统上。

桥接、 状态模式和策略模式 （在某种程度上包括适配器） 模式的接口非常相似。 实际上， 它们都基于组合模式——即将工作委派给其他对象， 不过也各自解决了不同的问题。 模式并不只是以特定方式组织代码的配方， 你还可以使用它们来和其他开发者讨论模式所解决的问题。

*/
/// Converts adaptee's specific interface to a compatible `Target` output.
pub struct TargetAdapter {
    // 封装 SpecificTarget
    adaptee: SpecificTarget,
}

impl TargetAdapter {
    pub fn new(adaptee: SpecificTarget) -> Self {
        Self { adaptee }
    }
}

// TargetAdapter 与 OrdinaryTarget 实现同一接口
impl Target for TargetAdapter {
    fn request(&self) -> String {
        // Here's the "adaptation" of a specific output to a compatible output.
        self.adaptee.specific_request().chars().rev().collect()
    }
}


#[cfg(test)]
mod chain {
    use crate::structx::adapter::adapter::TargetAdapter;
    use crate::structx::adapter::target::{OrdinaryTarget, SpecificTarget, Target};

    fn call(target: impl Target) {
        println!("'{}'", target.request());
    }

    #[test]
    fn main() {
        /// Calls any object of a `Target` trait.
        ///
        /// To understand the Adapter pattern better, imagine that this is
        /// a client code, which can operate over a specific interface only
        /// (`Target` trait only). It means that an incompatible interface cannot be
        /// passed here without an adapter.


        let target = OrdinaryTarget;

        print!("A compatible target can be directly called: ");
        call(target);

        let adaptee = SpecificTarget;

        println!(
            "Adaptee is incompatible with client: '{}'",
            adaptee.specific_request()
        );

        let adapter = TargetAdapter::new(adaptee);

        print!("But with adapter client can call its method: ");
        call(adapter);
    }

}